<?php

/**
 * redis utility.
 * 
 * api document.
 * https://github.com/phpredis/phpredis
 * 
 * @author Arlon
 *
 */
class RedisUtility
{

    public static $redis = null;
 // 是否重复抓取图片
    public static function getRedis($master = false, $default_db = 0)
    {
        if (self::$redis == null) {
            $redis_hosts = array();
            $host_array = array_filter(explode(';', Configure::read('Storage.redis_hosts')));
            if(empty($host_array)) {
                return null;
            }
            
            foreach ($host_array as $item) {
                $redis_hosts[] = explode(':', $item);
                if ($master) {
                    break; // master时，只取第一台配置的redis
                }
            }
            $nums = count($redis_hosts);
            do {
                $index = array_rand($redis_hosts);
                $ip = $redis_hosts[$index][0];
                $port = $redis_hosts[$index][1] ? $redis_hosts[$index][1] : '6379';
                $db = $redis_hosts[$index][2];
                /**
                 * *
                 * host: string.
                 * can be a host, or the path to a unix domain socket
                 * port: int, optional
                 * timeout: float, value in seconds (optional, default is 0 meaning unlimited)
                 * reserved: should be NULL if retry_interval is specified
                 * retry_interval: int, value in milliseconds (optional)
                 */
                self::$redis = null;
                self::$redis = new Redis();
                
                if ($connected = self::$redis->connect($ip, $port, 0.5, null, 100)) {
                    if (Configure::read('Storage.redis_auth')) {
                        try {
                            self::$redis->auth(Configure::read('Storage.redis_auth'));
                        } catch (Exception $e) {
                            unset($redis_hosts[$index]);
                            $nums --;
                            if ($nums > 0)
                                continue;
                            else
                                break;
                        }
                    }
                    if ($db > 0) { // 选择db
                        self::$redis->select($db);
                    }
                    break; // 连接成功返回
                } else {
                    // 连接失败：从库中剔除
                    self::$redis = null;
                    unset($redis_hosts[$index]);
                    $nums --;
                }
            } while ($nums > 0);
        }
        if (self::$redis && $default_db > 0) {
            self::$redis->select($default_db);
        }
        return self::$redis;
    }

    public static function expired($key, $time)
    {
        if ($redis = self::getRedis()) {
            return $redis->setTimeout($key, $time);
        }
        return false;
    }

    public static function get($key)
    {
        if ($redis = self::getRedis()) {
            return $redis->get($key);
        }
        return false;
    }

    /**
     * 设置key的值
     * 
     * @param unknown $key            
     * @param unknown $value            
     * @return boolean
     */
    public static function set($key, $value)
    {
        if ($redis = self::getRedis(true)) {
            return $redis->set($key, $value);
        }
        return false;
    }

    /**
     * 设置key的值，带失效时间
     * 
     * @param unknown $key            
     * @param unknown $value            
     * @param number $ttl
     *            失效时间，默认60秒
     * @return boolean
     */
    public static function setex($key, $value, $ttl = 300)
    {
        if ($redis = self::getRedis(true)) {
            return $redis->setex($key, $ttl, $value);
        }
        return false;
    }

    /**
     * ZADD key score member
     * Adds all the specified members with the specified scores to the sorted set stored at key.
     *
     * It is possible to specify multiple score / member pairs.
     * If a specified member is already a member of the sorted set,
     * the score is updated and the element reinserted at the right position to ensure the correct ordering.
     *
     * @param unknown $key            
     * @param unknown $score            
     * @param unknown $value
     *            member
     * @return boolean
     */
    public static function zAdd($key, $score, $value)
    {
        if ($redis = self::getRedis(true)) {
            return $redis->zAdd($key, $score, $value);
        }
        return false;
    }

    public static function zScore($key, $value)
    {
        if ($redis = self::getRedis(true)) {
            return $redis->zScore($key, $value);
        }
        return false;
    }

    public static function zRem($key, $value)
    {
        if ($redis = self::getRedis(true)) { // 选取master的redis主机
            return $redis->zRem($key, $value);
        }
        return false;
    }

    public static function zIncrBy($key, $num, $value)
    {
        if ($redis = self::getRedis(true)) {
            return $redis->zIncrBy($key, $num, $value);
        }
        return false;
    }

    /**
     * options = array(limit,page,withscore,sort,total)
     * 默认逆序;默认获取总数，total设为false时，不获取总数
     */
    public static function getZlist($key, $options)
    {
        if ($redis = self::getRedis()) {
            $page = $options['page'] ? $options['page'] : 1;
            $limit = $options['limit'] ? $options['limit'] : 10;
            $withscore = $options['withscore'] ? true : false;
            $start = ($page - 1) * $limit;
            $end = $start + $limit - 1;
            $ret = array();
            if (isset($options['sort']) && strtolower($options['sort']) == 'asc') {
                $ret['list'] = $redis->zRange($key, $start, $end, $withscore);
            } else { // desc
                $ret['list'] = $redis->zRevRange($key, $start, $end, $withscore);
            }
            if (! isset($options['sort']) || $options['sort'] !== false) {
                $ret['total'] = $redis->zCard($key); // 有序集合的元素个数
            }
            return $ret;
        } else {
            return array(
                'list' => array(),
                'total' => 0
            );
        }
    }

    /**
     * *
     * 返回合并后的总数
     */
    public static function zUnion($keyOutPut, $unionZKeys, $weights = array(), $AGGREGATE = "max")
    {
        if ($redis = self::getRedis(true)) {
            return $redis->zUnion($keyOutPut, $unionZKeys, $weights, $AGGREGATE);
        }
        return false;
    }
}
